﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Threading;

namespace Recrystallization
{
    public partial class Form1 : Form
    {
        private class clsCell
        {
            public int Model;
            public bool recrystallized;

            public clsCell()
            {
                Model = 0;
                recrystallized = false;
            }
        }


        private class clsCellGrain
        {
            private int model;
            public double deployment;
            public bool recrystallized;
            public Color colorGrain;
            public static List<Color> colorGrainList;
            public static uint grainNumber = 0;
            private static Random rand;

            public int Model
            {
                get
                {
                    return model;
                }
                set
                {
                    model = value;
                    if (model != 0) colorGrain = colorGrainList[model - 1];
                }
            }

            public void addNewGrain(int id)
            {
                    grainNumber++;
                    model = id;
                    colorGrainList.Add(Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255)));
                    colorGrain = colorGrainList[id - 1];
            }

            public void setGrain(int id)
            {
                    if (id > grainNumber)
                    {
                        grainNumber++;
                        colorGrainList.Add(Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255)));
                    }
                    model = id;
                    colorGrainList[id - 1] = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255));
                    colorGrain = colorGrainList[id - 1];
                    recrystallized = true;
            }

            public clsCellGrain()
            {
                model = 0;
                deployment = 0;
                recrystallized = false;
                colorGrainList = new List<Color>();
                colorGrain = new Color();
                rand = new Random();
            }
        }

        int sizeArea = 40, progress, recrystallizedGrainNumber;
        uint grainCount = 2;
        float width;
        double time;
        bool grainGrowthFirst;
        Graphics g;
        Pen pen;
        clsCellGrain[,] field;
        clsCell[,] fieldTMP;
        int[,] fieldGrain;
        uint[] neighbourGrain;
        Random rand;
        clsDeployment oDeployment;

        void declareField()
        {
            field = new clsCellGrain[sizeArea, sizeArea];
            fieldTMP = new clsCell[sizeArea, sizeArea];
            //for (uint i = 0; i < sizeArea; i++)
            Parallel.For(0, sizeArea, (i) =>
            {
                for (uint j = 0; j < sizeArea; j++)
                {
                    field[i, j] = new clsCellGrain();
                    fieldTMP[i, j] = new clsCell();
                }
            });
        }

        public Form1()
        {
            InitializeComponent();

            timer.Interval = 300;

            PiB.Image = new Bitmap(480, 480);
            g = Graphics.FromImage(PiB.Image);
            pen = new Pen(Color.Black);
            rand = new Random();

            width = (float)PiB.Width / (float)sizeArea;
            declareField();
            fieldGrain = new int[sizeArea, sizeArea];
            progress = (int)numGrain.Value;
            pgrGrowth.Maximum = (sizeArea * sizeArea);
            pgrGrowth.Value = progress;
            oDeployment = new clsDeployment(sizeArea, sizeArea);
            neighbourGrain = new uint[2];
            time = 0; recrystallizedGrainNumber = 0;
            numGrain.Maximum = sizeArea * sizeArea;
            grainGrowthFirst = true;

            setArea();
        }

        private void setArea(Boolean flag = true)
        {
            for (uint i = 0; i < sizeArea; i++)
            {
                for (uint j = 0; j < sizeArea; j++)
                {
                    if (flag)
                    {
                        field[i, j].Model = 0;
                        field[i, j].recrystallized = false;
                        field[i, j].deployment = 0;
                    }
                    else
                    {
                        field[i, j].Model = fieldGrain[i, j];
                        field[i, j].recrystallized = false;
                        field[i, j].deployment = 0;
                    }
                    g.FillRectangle(new SolidBrush(Color.Orange), i * width, j * width, width, width);
                }
            }

            //for (uint i = 0; i < neighbourGrain.Length; i++) neighbourGrain[i] = 0;
            Parallel.For(0, neighbourGrain.Length, (i) => neighbourGrain[i] = 0);

            //random grain
            if (rdbRandom.Checked && flag) randomGrain();
            //symetric grain
            else if (rdbSymetric.Checked && flag) symetricGrain();

            for (uint i = 0; i < sizeArea; i++)
            {
                for (uint j = 0; j < sizeArea; j++)
                {
                    if (field[i, j].Model != 0) g.FillRectangle(new SolidBrush(field[i, j].colorGrain), i * width, j * width, width, width);
                }
            }

            PiB.Refresh();
        }

        private void randomGrain()
        {
            grainCount = (uint)numGrain.Value;
            neighbourGrain = new uint[grainCount];
            int x = 0, y = 0;

            clearFieldGrain();
            clsCellGrain.colorGrainList.Clear();
            clsCellGrain.grainNumber = 0;
            for (uint i = 0; i < grainCount; i++)
            {
                int control = 0;
                do
                {
                    control++;
                    if (control == 100)
                    {
                        MessageBox.Show("Radius is too great!\nNumber of grain was reduced to " + clsCellGrain.grainNumber, "Radius warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        numGrain.Value = clsCellGrain.grainNumber + 1;
                        grainCount = (uint)clsCellGrain.grainNumber + 1;
                        btnNextStep.Enabled = true;
                        btnStart.Enabled = true;
                        btnStop.Enabled = true;
                        progress = (int)numGrain.Value;
                        pgrGrowth.Value = (int)numGrain.Value;

                        break;
                    }
                    x = rand.Next(1, sizeArea - 1);
                    y = rand.Next(1, sizeArea - 1);
                }
                while (checkRadius(x, y, (int)numRadiusNucl.Value));

                fieldGrain[x, y] = (int)i + 1;
                field[x, y].addNewGrain((int)i + 1);
            }
        }

        private bool checkRadius(int x, int y, int radius)
        {
            int tmpI, tmpJ;
            for (int i = x - (int)radius; i <= x + (int)radius; i++)
            {
                for (int j = y - (int)radius; j <= y + (int)radius; j++)
                {
                    if (!checkPeriodic.Checked)
                    {
                        if (i >= 0 && i < sizeArea && j >= 0 && j < sizeArea)
                            if ((field[i, j].Model != 0 /*&& !setDeploy*/) || (field[i, j].deployment >= oDeployment.critical_sigma /*&& setDeploy*/ && i != x && j != y))
                                return true;
                    }
                    else
                    {
                        tmpI = i; tmpJ = j;
                        if (i < 0) tmpI = sizeArea + i;
                        if (j < 0) tmpJ = sizeArea + j;
                        if (i >= sizeArea) tmpI = i - sizeArea;
                        if (j >= sizeArea) tmpJ = j - sizeArea;

                        if ((field[tmpI, tmpJ].Model != 0 /*&& !setDeploy*/) || (field[tmpI, tmpJ].deployment >= oDeployment.critical_sigma /*&& setDeploy*/ && i != x && j != y)) return true;
                    }
                }
            }
            return false;
        }

        void clearFieldGrain()
        {
            //for (uint i = 0; i < sizeArea; i++)
            Parallel.For(0, sizeArea, (i) =>
            {
                for (uint j = 0; j < sizeArea; j++)
                    fieldGrain[i, j] = 0;
            });
        }

        private void symetricGrain()
        {
            grainCount = (uint)numGrain.Value;
            neighbourGrain = new uint[grainCount];
            clsCellGrain.colorGrainList.Clear();
            clsCellGrain.grainNumber = 0;

            clearFieldGrain();

            double ceiling = Math.Sqrt((double)grainCount);
            int areaDimension = sizeArea / (int)Math.Ceiling(ceiling);
            int grainType = 1;

            for (int i = areaDimension / 2; i < hScrollBar1.Value; i += areaDimension)
            {
                for (int j = areaDimension / 2; j < hScrollBar1.Value; j += areaDimension)
                {
                    if (grainType <= grainCount)
                    {
                        fieldGrain[j, i] = grainType;
                        field[j, i].addNewGrain(grainType);
                        grainType++;
                    }
                    else break;
                }
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            stepGrainGrowth();
            if (!grainGrowthFirst && rdbRecrystall.Checked)
                setDeployment();
            else if (rdbMonteCarlo.Checked) monteCarlo();
        }

        private void btnNextStep_Click(object sender, EventArgs e)
        {
            stlStatus.Text = "One step";
            stepGrainGrowth();
        }

        private void chooseRule(uint i, uint j, int random)
        {
            if (rdbMoore.Checked) countNeighbourMoore(i, j);
            else if (rdbNeumann.Checked) countNeighbourVonNeumann(i, j);
            else if (rdbHexLeft.Checked) countNeighbourHexagonalLeft(i, j);
            else if (rdbHexRight.Checked) countNeighbourHexagonalRight(i, j);
            else if (rdbHexRand.Checked)
            {
                int r = rand.Next();
                if (r % 2 == 0) countNeighbourHexagonalLeft(i, j);
                else countNeighbourHexagonalRight(i, j);
            }
            else if (rdbPentagonal.Checked) countNeighbourPentagonal(i, j, random);

            int max = maxNeighbour();
            if (max != -1)
            {
                fieldTMP[i, j].Model = max + 1;
                if (!grainGrowthFirst)
                {
                    fieldTMP[i, j].recrystallized = true;
                    pgrGrowth.Value++;
                }
            }
        }

        void stepGrainGrowth()
        {
            int random = rand.Next(4);
            progress = 0;
            for (uint i = 0; i < sizeArea; i++)
            {
                for (uint j = 0; j < sizeArea; j++)
                {
                    if (field[i, j].Model == 0) chooseRule(i, j, random);
                    else if (!field[i, j].recrystallized && !grainGrowthFirst) chooseRule(i, j, random);

                    //for (uint k = 0; k < neighbourGrain.Length; k++) neighbourGrain[k] = 0;
                    Parallel.For(0, neighbourGrain.Length, k =>neighbourGrain[k] = 0);

                    if (field[i, j].Model == 0 && grainGrowthFirst) progress++;
                    else if (!field[i, j].recrystallized && !grainGrowthFirst) progress++;
                    if (fieldTMP[i, j].Model != 0 && grainGrowthFirst)
                    {
                        g.FillRectangle(new SolidBrush(clsCellGrain.colorGrainList[fieldTMP[i, j].Model - 1]), i * width, j * width, width, width);
                    }
                    else if (!grainGrowthFirst && fieldTMP[i, j].recrystallized) g.FillRectangle(new SolidBrush(clsCellGrain.colorGrainList[fieldTMP[i, j].Model - 1]), i * width, j * width, width, width);
                }
            }

            
            if (progress == 0 && grainGrowthFirst)
            {
                if (grainGrowthFirst) pgrGrowth.Value = 0;
                grainGrowthFirst = false;
                stlStatus.Text = "Grain expanded!";
            }
            else if (progress <= pgrGrowth.Maximum && grainGrowthFirst) pgrGrowth.Value = ((sizeArea * sizeArea) - progress);
            else if (progress == 0 && !grainGrowthFirst)
            {
                stlStatus.Text = "Recrystallized is finished!";
                timer.Stop();
            }

            AssignField();
            PiB.Refresh();
        }

        void setDeployment()
        {
            stlStatus.Text = "Deployment is setting...";
            oDeployment.calculateCRITICALro(sizeArea, sizeArea);
            do
            {
                time += Double.Parse(txtDeplTime.Text);
                oDeployment.calculateAverageDELTAro(sizeArea, sizeArea, time);
                for (uint i = 0; i < sizeArea; i++)
                {
                    for (uint j = 0; j < sizeArea; j++)
                    {
                        if (grainOnBoard(i, j) && !field[i, j].recrystallized)
                            field[i, j].deployment += oDeployment.getDeploymentForGrain(true);
                        else if (!field[i, j].recrystallized) field[i, j].deployment += oDeployment.getDeploymentForGrain(false);

                        if (field[i, j].deployment > oDeployment.critical_sigma && !field[i, j].recrystallized)
                        {
                            field[i, j].setGrain(++recrystallizedGrainNumber);
                            fieldTMP[i, j].Model = recrystallizedGrainNumber;
                            fieldTMP[i, j].recrystallized = true;
                            g.FillRectangle(new SolidBrush(field[i, j].colorGrain), i * width, j * width, width, width);
                        }
                    }
                }
            } while (recrystallizedGrainNumber == 0);

            neighbourGrain = new uint[recrystallizedGrainNumber];
            //for (uint k = 0; k < recrystallizedGrainNumber; k++) neighbourGrain[k] = 0;
            Parallel.For(0, recrystallizedGrainNumber, k => neighbourGrain[k] = 0);
            stlStatus.Text = "Grain is expanding after deployment...";
        }

        private void monteCarlo()
        {

        }

        private int maxNeighbour()
        {
            List<int> max = new List<int>();
            max.Add(0);     //contain index

            for (uint i = 1; i < neighbourGrain.Length; i++)
            {
                if (neighbourGrain[max[max.Count - 1]] < neighbourGrain[i])
                {
                    max.Clear();
                    max.Add((int)i);
                }
                else if (neighbourGrain[max[max.Count - 1]] == neighbourGrain[i]) max.Add((int)i);
            }
            if (neighbourGrain[max[max.Count - 1]] == 0) return -1;
            else return max[rand.Next(max.Count - 1)];
        }

        private bool grainOnBoard(uint i, uint j)
        {
            if (retLessIndex(i) != -1)
                if (field[retLessIndex(i), j].Model != field[i, j].Model) return true;
            if (retLessIndex(i) != -1 && retLessIndex(j) != -1)
                if (field[retLessIndex(i), retLessIndex(j)].Model != field[i, j].Model) return true;
            if (retLessIndex(i) != -1 && retGreaterIndex(j) != -1)
                if (field[retLessIndex(i), retGreaterIndex(j)].Model != field[i, j].Model) return true;
            if (retGreaterIndex(i) != -1)
                if (field[retGreaterIndex(i), j].Model != field[i, j].Model) return true;
            if (retGreaterIndex(i) != -1 && retLessIndex(j) != -1)
                if (field[retGreaterIndex(i), retLessIndex(j)].Model != field[i, j].Model) return true;
            if (retGreaterIndex(i) != -1 && retGreaterIndex(j) != -1)
                if (field[retGreaterIndex(i), retGreaterIndex(j)].Model != field[i, j].Model) return true;
            if (retGreaterIndex(j) != -1)
                if (field[i, retGreaterIndex(j)].Model != field[i, j].Model) return true;
            if (retLessIndex(j) != -1)
                if (field[i, retLessIndex(j)].Model != field[i, j].Model) return true;

            return false;
        }

        private void countNeighbourMoore(uint i, uint j)
        {
            //for (uint k = 0; k < neighbourGrain.Length; k++)
            Parallel.For(0, neighbourGrain.Length, k =>
            {
                if (retLessIndex(i) != -1)
                    if (field[retLessIndex(i), j].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retLessIndex(i), j].recrystallized) neighbourGrain[k]++;
                if (retLessIndex(i) != -1 && retLessIndex(j) != -1)
                    if (field[retLessIndex(i), retLessIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retLessIndex(i), retLessIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retLessIndex(i) != -1 && retGreaterIndex(j) != -1)
                    if (field[retLessIndex(i), retGreaterIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retLessIndex(i), retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(i) != -1)
                    if (field[retGreaterIndex(i), j].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retGreaterIndex(i), j].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(i) != -1 && retLessIndex(j) != -1)
                    if (field[retGreaterIndex(i), retLessIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retGreaterIndex(i), retLessIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(i) != -1 && retGreaterIndex(j) != -1)
                    if (field[retGreaterIndex(i), retGreaterIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retGreaterIndex(i), retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(j) != -1)
                    if (field[i, retGreaterIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[i, retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retLessIndex(j) != -1)
                    if (field[i, retLessIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[i, retLessIndex(j)].recrystallized) neighbourGrain[k]++;
            });
        }

        private void countNeighbourVonNeumann(uint i, uint j)
        {
            //for (uint k = 0; k < neighbourGrain.Length; k++)
            Parallel.For(0, neighbourGrain.Length, k =>
            {
                if (retLessIndex(i) != -1)
                    if (field[retLessIndex(i), j].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retLessIndex(i), j].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(i) != -1)
                    if (field[retGreaterIndex(i), j].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retGreaterIndex(i), j].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(j) != -1)
                    if (field[i, retGreaterIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[i, retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retLessIndex(j) != -1)
                    if (field[i, retLessIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[i, retLessIndex(j)].recrystallized) neighbourGrain[k]++;
            });
        }

        private void countNeighbourHexagonalLeft(uint i, uint j)
        {
            //for (uint k = 0; k < neighbourGrain.Length; k++)
            Parallel.For(0, neighbourGrain.Length, k =>
            {
                if (retLessIndex(i) != -1)
                    if (field[retLessIndex(i), j].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retLessIndex(i), j].recrystallized) neighbourGrain[k]++;
                if (retLessIndex(i) != -1 && retLessIndex(j) != -1)
                    if (field[retLessIndex(i), retLessIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retLessIndex(i), retLessIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(i) != -1)
                    if (field[retGreaterIndex(i), j].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retGreaterIndex(i), j].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(i) != -1 && retGreaterIndex(j) != -1)
                    if (field[retGreaterIndex(i), retGreaterIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retGreaterIndex(i), retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(j) != -1)
                    if (field[i, retGreaterIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[i, retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retLessIndex(j) != -1)
                    if (field[i, retLessIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[i, retLessIndex(j)].recrystallized) neighbourGrain[k]++;
            });
        }

        private void countNeighbourHexagonalRight(uint i, uint j)
        {
            //for (uint k = 0; k < neighbourGrain.Length; k++)
            Parallel.For(0, neighbourGrain.Length, k =>
            {
                if (retLessIndex(i) != -1)
                    if (field[retLessIndex(i), j].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retLessIndex(i), j].recrystallized) neighbourGrain[k]++;
                if (retLessIndex(i) != -1 && retGreaterIndex(j) != -1)
                    if (field[retLessIndex(i), retGreaterIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retLessIndex(i), retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(i) != -1)
                    if (field[retGreaterIndex(i), j].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retGreaterIndex(i), j].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(i) != -1 && retLessIndex(j) != -1)
                    if (field[retGreaterIndex(i), retLessIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[retGreaterIndex(i), retLessIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retGreaterIndex(j) != -1)
                    if (field[i, retGreaterIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[i, retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                if (retLessIndex(j) != -1)
                    if (field[i, retLessIndex(j)].Model == k + 1)
                        if (grainGrowthFirst) neighbourGrain[k]++;
                        else if (field[i, retLessIndex(j)].recrystallized) neighbourGrain[k]++;
            });
        }

        private void countNeighbourPentagonal(uint i, uint j, int random)
        {
            //for (uint k = 0; k < neighbourGrain.Length; k++)
            Parallel.For(0, neighbourGrain.Length, k =>
            {
                if (random == 0 || random == 2 || random == 3)
                {
                    if (retLessIndex(i) != -1)
                        if (field[retLessIndex(i), j].Model == k + 1)
                            if (grainGrowthFirst) neighbourGrain[k]++;
                            else if (field[retLessIndex(i), j].recrystallized) neighbourGrain[k]++;
                }
                if (random == 0 || random == 3)
                {
                    if (retLessIndex(i) != -1 && retLessIndex(j) != -1)
                        if (field[retLessIndex(i), retLessIndex(j)].Model == k + 1)
                            if (grainGrowthFirst) neighbourGrain[k]++;
                            else if (field[retLessIndex(i), retLessIndex(j)].recrystallized) neighbourGrain[k]++;
                }
                if (random == 0 || random == 2)
                {
                    if (retLessIndex(i) != -1 && retGreaterIndex(j) != -1)
                        if (field[retLessIndex(i), retGreaterIndex(j)].Model == k + 1)
                            if (grainGrowthFirst) neighbourGrain[k]++;
                            else if (field[retLessIndex(i), retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                }
                if (random == 1 || random == 2 || random == 3)
                {
                    if (retGreaterIndex(i) != -1)
                        if (field[retGreaterIndex(i), j].Model == k + 1)
                            if (grainGrowthFirst) neighbourGrain[k]++;
                            else if (field[retGreaterIndex(i), j].recrystallized) neighbourGrain[k]++;
                }
                if (random == 1 || random == 3)
                {
                    if (retGreaterIndex(i) != -1 && retLessIndex(j) != -1)
                        if (field[retGreaterIndex(i), retLessIndex(j)].Model == k + 1)
                            if (grainGrowthFirst) neighbourGrain[k]++;
                            else if (field[retGreaterIndex(i), retLessIndex(j)].recrystallized) neighbourGrain[k]++;
                }
                if (random == 1 || random == 2)
                {
                    if (retGreaterIndex(i) != -1 && retGreaterIndex(j) != -1)
                        if (field[retGreaterIndex(i), retGreaterIndex(j)].Model == k + 1)
                            if (grainGrowthFirst) neighbourGrain[k]++;
                            else if (field[retGreaterIndex(i), retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                }
                if (random == 0 || random == 1 || random == 2)
                {
                    if (retGreaterIndex(j) != -1)
                        if (field[i, retGreaterIndex(j)].Model == k + 1)
                            if (grainGrowthFirst) neighbourGrain[k]++;
                            else if (field[i, retGreaterIndex(j)].recrystallized) neighbourGrain[k]++;
                }
                if (random == 0 || random == 1 || random == 3)
                {
                    if (retLessIndex(j) != -1)
                        if (field[i, retLessIndex(j)].Model == k + 1)
                            if (grainGrowthFirst) neighbourGrain[k]++;
                            else if (field[i, retLessIndex(j)].recrystallized) neighbourGrain[k]++;
                }
            });
        }

        private int retLessIndex(uint x)
        {
            if (checkPeriodic.Checked)
            {
                if (((int)x - 1) < 0) return sizeArea - 1;
                else return (int)x - 1;
            }
            else
            {
                if (((int)x - 1) < 0) return -1;
                else return (int)x - 1;
            }
        }

        private int retGreaterIndex(uint x)
        {
            if (checkPeriodic.Checked)
            {
                if (((int)x + 1) > sizeArea - 1) return 0;
                else return ((int)x + 1) % sizeArea;
            }
            else
            {
                if (((int)x + 1) > sizeArea - 1) return -1;
                else return (int)x + 1;
            }
        }

        private void AssignField()
        {
            for (uint i = 0; i < sizeArea; i++)
            {
                for (uint j = 0; j < sizeArea; j++)
                {
                    field[i, j].Model = fieldTMP[i, j].Model;
                    if (!grainGrowthFirst) field[i, j].recrystallized = fieldTMP[i, j].recrystallized;
                }
            }
        }

        private void start_Click(object sender, EventArgs e)
        {
            if (rdbRandom.Checked) grainCount = (uint)numGrain.Value;
            neighbourGrain = new uint[grainCount];
            hScrollBar1.Enabled = false;
            stlStatus.Text = "Grain is expanding...";
            timer.Start();
        }

        private void stop_Click(object sender, EventArgs e)
        {
            hScrollBar1.Enabled = true;
            stlStatus.Text = "Stopped!";
            timer.Stop();
        }

        private void reset_Click(object sender, EventArgs e)
        {
            hScrollBar1.Enabled = true;
            timer.Stop();
            stlStatus.Text = "Resetted!";
            pgrGrowth.Value = progress = 0;
            recrystallizedGrainNumber = 0;
            time = 0;
            clsCellGrain.grainNumber = 0;
            grainGrowthFirst = true;
            clearFieldGrain();
            declareField();
            setArea(false);
        }

        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            sizeArea = hScrollBar1.Value;
            oDeployment.calculateCRITICALro(sizeArea, sizeArea);
            pgrGrowth.Maximum = (sizeArea * sizeArea);
            pgrGrowth.Value = (int)numGrain.Value;
            width = (float)PiB.Width / (float)sizeArea;
            declareField();
            fieldGrain = new int[sizeArea, sizeArea];
            setArea();
        }

        private void PiB_MouseDown(object sender, MouseEventArgs e)
        {
            if (rdbManual.Checked)
            {
                int posX = (int)((e.X - (e.X % width)) / width);
                int posY = (int)((e.Y - (e.Y % width)) / width);

                fieldGrain[posX, posY] = (int)clsCellGrain.grainNumber + 1;
                field[posX, posY].addNewGrain((int)clsCellGrain.grainNumber + 1);

                g.FillRectangle(new SolidBrush(clsCellGrain.colorGrainList[(int)clsCellGrain.grainNumber - 1]), posX * width, posY * width, width, width);
                grainCount++;
                neighbourGrain = new uint[(int)clsCellGrain.grainNumber];

                PiB.Refresh();
            }
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.MessageBox.Show("Grain Growth application\nAuthor: Paweł paweln66 Nowak\nCopyright © AGH WIMiIP 2012", "About",
                       System.Windows.Forms.MessageBoxButtons.OK,
                       System.Windows.Forms.MessageBoxIcon.Information);
        }

        private void numRand_ValueChanged(object sender, EventArgs e)
        {
            btnNextStep.Enabled = false;
            btnStart.Enabled = false;
            btnStop.Enabled = false;
        }

        private void btnSet_Click(object sender, EventArgs e)
        {
            btnNextStep.Enabled = true;
            btnStart.Enabled = true;
            btnStop.Enabled = true;
            progress = (int)numGrain.Value;
            pgrGrowth.Value = (int)numGrain.Value;

            if (rdbManual.Checked)
            {
                clsCellGrain.colorGrainList.Clear();
                clsCellGrain.grainNumber = 0;
            }
            setArea();
        }

        private void rdbManual_CheckedChanged(object sender, EventArgs e)
        {
            clearFieldGrain();
        }

        private void saveMapAsPictureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter = "bmp|*.bmp";
            dialog.ShowDialog();
            if (dialog.FileName != "")
                PiB.Image.Save(dialog.FileName);
        }

        private void repositoryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string target = "http://code.google.com/p/multiscale-modelling-recrystallization/";
            //Use no more than one assignment when you test this code. 
            //string target = "ftp://ftp.microsoft.com";
            //string target = "C:\\Program Files\\Microsoft Visual Studio\\INSTALL.HTM"; 

            try
            {
                System.Diagnostics.Process.Start(target);
            }
            catch
                (
                 System.ComponentModel.Win32Exception noBrowser)
            {
                if (noBrowser.ErrorCode == -2147467259)
                    MessageBox.Show(noBrowser.Message);
            }
            catch (System.Exception other)
            {
                MessageBox.Show(other.Message);
            }
        }
    }
}
